package com.cheche.dn.common.base;

import com.cheche.dn.Result;
import com.cheche.dn.domain.Apis;
import com.cheche.dn.domain.admin.Admin;
import com.cheche.dn.domain.user.User;
import com.cheche.dn.error.ErrorCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.Set;

/**
 * Controller - 基类
 * Created by cheshun on 15/8/5.
 */
public abstract class BaseController implements Apis {

    /** "验证结果"参数名称 */
    private static final String CONSTRAINT_VIOLATIONS_ATTRIBUTE_NAME = "constraintViolations";

    @Resource(name = "validator")
    private Validator validator;
    @Autowired
    protected Service service;

    /**
     * 数据验证
     *
     * @param target
     *            验证对象
     * @param groups
     *            验证组
     * @return 验证结果
     */
    protected boolean isValid(Object target, Class<?>... groups) {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target, groups);
        if (constraintViolations.isEmpty()) {
            return true;
        } else {
            RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
            requestAttributes.setAttribute(CONSTRAINT_VIOLATIONS_ATTRIBUTE_NAME, constraintViolations, RequestAttributes.SCOPE_REQUEST);
            return false;
        }
    }

    /**
     * 数据验证
     *
     * @param type
     *            类型
     * @param property
     *            属性
     * @param value
     *            值
     * @param groups
     *            验证组
     * @return 验证结果
     */
    @SuppressWarnings("unchecked")
    protected boolean isValid(Class<?> type, String property, Object value, Class<?>... groups) {
        Set<?> constraintViolations = validator.validateValue(type, property, value, groups);
        if (constraintViolations.isEmpty()) {
            return true;
        } else {
            RequestAttributes requestAttributes = currentRequestAttributes();
            Set objects = (Set) requestAttributes.getAttribute(CONSTRAINT_VIOLATIONS_ATTRIBUTE_NAME, RequestAttributes.SCOPE_REQUEST);
            if (objects != null) {
                constraintViolations.addAll(objects);
            }
            requestAttributes.setAttribute(CONSTRAINT_VIOLATIONS_ATTRIBUTE_NAME, constraintViolations, RequestAttributes.SCOPE_REQUEST);
            return false;
        }
    }

    protected RequestAttributes currentRequestAttributes() {
        return RequestContextHolder.currentRequestAttributes();
    }

    protected HttpServletRequest currentRequest() {
        return ((ServletRequestAttributes) currentRequestAttributes()).getRequest();
    }

    protected HttpServletResponse currentResponse() {
        return ((ServletRequestAttributes) currentRequestAttributes()).getResponse();
    }

    protected User currentUser() {
        User user = (User) currentRequest().getAttribute(User.class.getName());
        if (user == null) return null;
        return service.find(User.class, user.getId());
    }

    protected Admin currentAdmin() {
        Admin admin = (Admin) currentRequest().getAttribute(Admin.class.getName());
        if (admin == null) return null;
        return service.find(Admin.class, admin.getId());
    }

    protected Result currentValidError() {
        Set<?> constraintViolations = (Set<?>) currentRequestAttributes().getAttribute(
                CONSTRAINT_VIOLATIONS_ATTRIBUTE_NAME, RequestAttributes.SCOPE_REQUEST
        );
        String errorMessage = "";
        for (Object o : constraintViolations) {
            ConstraintViolation constraintViolation = (ConstraintViolation) o;
            errorMessage += String.format("param %s %s ",
                    constraintViolation.getPropertyPath().toString(), constraintViolation.getMessage());
        }
        return Result.error(ErrorCode.ERROR, errorMessage);
    }

    /**
     * 数据类型(Data Types)
     */
    public interface Dt {
        String PAGE = "page";
        String LIST = "list";
    }
}
